/**
 * 
 */
package com.qb.mobile.manager;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;

import com.qb.mobile.model.Address;
import com.qb.mobile.model.Email;
import com.qb.mobile.model.Group;
import com.qb.mobile.model.InstantMessenger;
import com.qb.mobile.model.Organization;
import com.qb.mobile.model.Phone;
import com.qb.mobile.model.Phonebook;
import com.qb.mobile.model.Photo;

/**
 * @author <a href="mailto:dangcongthanhtrung@gmail.com">dangtrung</a>
 * 
 *         ContactManager.java class
 * 
 */
public class ContactsSystem {

	private ContentResolver contentResolver;
	private List<Phonebook> list;

	private String[] groupsProjection = new String[] {
			ContactsContract.Groups._ID, ContactsContract.Groups.SYSTEM_ID,
			ContactsContract.Groups.TITLE,
			ContactsContract.Groups.ACCOUNT_NAME,
			ContactsContract.Groups.ACCOUNT_TYPE };

	/**
	 * @param context
	 * @param list
	 */
	public ContactsSystem(Context context, List<Phonebook> list) {
		this.contentResolver = context.getContentResolver();
		this.list = new ArrayList<Phonebook>();
		this.list = list;
	}

	/**
	 * @param context
	 */
	public ContactsSystem(Context context) {
		this.contentResolver = context.getContentResolver();
	}

	/**
	 * @return list of Phonebook
	 */
	public List<Phonebook> newContactList() {
		
		Cursor cur = this.contentResolver.query(
				ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
		if (cur.getCount() > 0) {
			while (cur.moveToNext()) {
				Phonebook c = new Phonebook();
				String id = cur.getString(cur
						.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
				c.setId(id);
				c.setName(cur.getString(cur
						.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)));
				
				if (Integer.parseInt(cur.getString(cur.getColumnIndexOrThrow(
						ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
					ArrayList<Phone> list = this.queryAllPhoneNumbersForContact(id);
					if (list.size() > 0)
						c.setPhones(list);
				}
				c.setEmails(this.queryAllEmailAddressesForContact(id));
				c.setNotes(this.queryNotesForContact(id));
				c.setAddresses(this.queryAddressesForContact(id));
				c.setImAddresses(this.queryInstantMessengerForContact(id));
				c.setOrganization(this.queryOrganizationForContact(id));
				c.setPhoto(this.queryPhotoForContact(id));
				list.add(c);
			}
		}
		cur.close();
		return list;
	}

	/**
	 * @param id
	 * @return Phonebook's object Phonebook
	 */
	public Phonebook getPhonebookById(String id) {
		Cursor cur = contentResolver.query(
				ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
		if (cur.getCount() > 0) {
			while (cur.moveToNext()) {
				String idCon = cur.getString(cur
						.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
				if (idCon.equals(id)) {
					Phonebook c = new Phonebook();
					c.setId(id);
					c.setName(cur.getString(cur
							.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)));
					if (Integer
							.parseInt(cur.getString(cur
									.getColumnIndexOrThrow(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
						ArrayList<Phone> list = this
								.queryAllPhoneNumbersForContact(id);
						if (list.size() > 0)
							c.setPhones(list);
					}
					c.setEmails(this.queryAllEmailAddressesForContact(id));
					c.setNotes(this.queryNotesForContact(id));
					c.setAddresses(this.queryAddressesForContact(id));
					c.setImAddresses(this.queryInstantMessengerForContact(id));
					c.setOrganization(this.queryOrganizationForContact(id));
					c.setPhoto(this.queryPhotoForContact(id));
					return c;
				}
			}
		}
		cur.close();
		return null;
	}

	/**
	 * 
	 * @param contactId
	 */
	private Photo queryPhotoForContact(String id) {
		Photo photo = null;

		String[] projection = new String[] { Contacts.DISPLAY_NAME,
				Contacts.PHOTO_ID };
		Cursor contact = contentResolver.query(Contacts.CONTENT_URI,
				projection, Contacts._ID + "=?", new String[] { id }, null);

		if (contact.moveToFirst()) {
			String photoId = contact.getString(contact
					.getColumnIndexOrThrow(Contacts.PHOTO_ID));
			byte[] bitmapPhoto;
			if (photoId != null) {
				bitmapPhoto = queryContactBitmap(photoId);
				photo = new Photo(bitmapPhoto, photoId);
			} else {
				photo = null;
			}
		}
		contact.close();
		return photo;
	}

	/**
	 * 
	 * @param photoId
	 * @return
	 */
	private byte[] queryContactBitmap(String photoId) {
		String[] projection = new String[] { CommonDataKinds.Photo.PHOTO };
		Cursor photo = contentResolver.query(Data.CONTENT_URI, projection,
				Data._ID + "=?", new String[] { photoId }, null);
		byte[] photoBlob = null;
		if (photo.moveToFirst()) {
			photoBlob = photo.getBlob(photo
					.getColumnIndexOrThrow(CommonDataKinds.Photo.PHOTO));
		}
		photo.close();
		return photoBlob;
	}

	/**
	 * Phone numbers are stored in their own table and need to be queried
	 * separately. To query the phone number table use the URI stored in the SDK
	 * variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE
	 * conditional to get the phone numbers for the specified contact.
	 * 
	 * @param contactId
	 */
	private ArrayList<Phone> queryAllPhoneNumbersForContact(String id) {
		ArrayList<Phone> phones = new ArrayList<Phone>();

		Cursor pCur = this.contentResolver.query(
				ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
				ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
				new String[] { id }, null);
		while (pCur.moveToNext()) {
			String phone = pCur
					.getString(pCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
			int type = pCur
					.getInt(pCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.TYPE));
			if (phone != null && phone.length() > 0)
				phones.add(new Phone(phone, type));
		}
		pCur.close();
		return (phones);
	}

	/**
	 * Querying email addresses is similar to phone numbers. A query must be
	 * performed to get email addresses from the database. Query the URI stored
	 * in ContactsContract.CommonDataKinds.Email.CONTENT_URI to query the email
	 * address table.
	 * 
	 * @param contactId
	 */
	private ArrayList<Email> queryAllEmailAddressesForContact(String id) {

		ArrayList<Email> emailList = new ArrayList<Email>();
		String[] projection = new String[] {
				ContactsContract.CommonDataKinds.Email.DATA,
				ContactsContract.CommonDataKinds.Email.TYPE };

		Cursor emails = this.contentResolver.query(
				ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection,
				Data.CONTACT_ID + "=?", new String[] { id }, null);

		while (emails.moveToNext()) {
			String email = emails
					.getString(emails
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.DATA));
			int type = emails
					.getInt(emails
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.TYPE));
			Email mail = new Email(email, type);
			emailList.add(mail);
		}
		emails.close();
		return emailList;
	}

	/**
	 * Android can store multiple postal addresses per contact. Addresses are
	 * also stored in the data table like notes and queried via the URI stored
	 * in ContactsContract.Data.CONTENT_URI
	 * 
	 * @param contactId
	 * @param phonebook
	 * @return Phonebook
	 */
	private ArrayList<Address> queryAddressesForContact(String id) {

		ArrayList<Address> addrList = new ArrayList<Address>();

		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] whereParameters = new String[] {
				id,
				ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE };

		Cursor addrCur = this.contentResolver.query(
				ContactsContract.Data.CONTENT_URI, null, where,
				whereParameters, null);
		while (addrCur.moveToNext()) {
			String poBox = addrCur
					.getString(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POBOX));
			String street = addrCur
					.getString(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.STREET));
			String city = addrCur
					.getString(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.CITY));
			String state = addrCur
					.getString(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.REGION));
			String postalCode = addrCur
					.getString(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE));
			String country = addrCur
					.getString(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY));
			int type = addrCur
					.getInt(addrCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.TYPE));
			Address a = new Address(poBox, street, city, state, postalCode,
					country, type);
			addrList.add(a);
		}
		addrCur.close();
		return (addrList);
	}

	/**
	 * The instant messenger query performs just as the notes and address
	 * queries. Important field names for IM related data are stored in
	 * ContactsContract.CommonDataKinds.Im.
	 * 
	 * @param contactId
	 */
	private ArrayList<InstantMessenger> queryInstantMessengerForContact(
			String id) {

		ArrayList<InstantMessenger> imList = new ArrayList<InstantMessenger>();

		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";

		String[] whereParameters = new String[] { id,
				ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE };

		Cursor imCur = this.contentResolver.query(
				ContactsContract.Data.CONTENT_URI, null, where,
				whereParameters, null);

		if (imCur.moveToNext()) {
			String imName = imCur.getString(imCur
					.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Im.DATA));
			String imType = imCur.getString(imCur
					.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Im.TYPE));
			if (imName.length() > 0) {
				InstantMessenger im = new InstantMessenger(imName, imType);
				imList.add(im);
			}
		}
		imCur.close();
		return (imList);
	}

	/**
	 * The last part of the contact record to be covered is the Organizations
	 * data. The Android contact record can contain information about
	 * Employment, professional, and social memberships as well as roles and
	 * titles. These records are queried from the URI stored in
	 * ContactsContract.Data.CONTENT_URI. Important field names for the
	 * organization data are stored in
	 * ContactsContract.CommonDataKinds.Organization.
	 * 
	 * @param contactId
	 * @return Organization
	 */
	private Organization queryOrganizationForContact(String id) {
		Organization org = new Organization();

		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";

		String[] whereParameters = new String[] { id,
				ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE };

		Cursor orgCur = this.contentResolver.query(
				ContactsContract.Data.CONTENT_URI, null, where,
				whereParameters, null);

		if (orgCur.moveToFirst()) {
			String orgName = orgCur
					.getString(orgCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.DATA));
			String title = orgCur
					.getString(orgCur
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.TITLE));
			if (orgName.length() > 0) {
				org.setOrganization(orgName);
				org.setTitle(title);
			}
		}
		orgCur.close();
		return (org);
	}

	/**
	 * Custom notes can be attached to each contact record. As before these are
	 * stored in a separate table and are related based on the contact ID.
	 * 
	 * @param contactId
	 */
	private ArrayList<String> queryNotesForContact(String id) {
		ArrayList<String> strList = new ArrayList<String>();
		
		String noteWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
		
		String[] noteWhereParams = new String[] { id, CommonDataKinds.Note.CONTENT_ITEM_TYPE };
		
		Cursor noteCur = contentResolver.query(Data.CONTENT_URI, null,
				noteWhere, noteWhereParams, null);
		
		if (noteCur.moveToFirst()) {
			String note = noteCur.getString(noteCur
					.getColumnIndexOrThrow(CommonDataKinds.Note.NOTE));
			strList.add(note);
		}
		noteCur.close();
		return strList;
	}

	public ArrayList<Group> queryAllGroups() {

		ArrayList<Group> groupList = new ArrayList<Group>();

		Cursor cursor = contentResolver.query(
				ContactsContract.Groups.CONTENT_URI, groupsProjection, null,
				null, ContactsContract.Groups._ID + " ASC");

		while (cursor.moveToNext()) {
			Group group = new Group();

			String gTitle = (cursor.getString(cursor
					.getColumnIndexOrThrow(ContactsContract.Groups.TITLE)));

			if (gTitle.contains("Group:")) {
				gTitle = gTitle.substring(gTitle.indexOf("Group:") + 6).trim();

			}
			if (gTitle.contains("Favorite_")) {
				gTitle = "Favorites";
			}
			if (gTitle.contains("Starred in Android")
					|| gTitle.contains("My Contacts")) {
				continue;
			}

			group.setId(cursor.getString(cursor
					.getColumnIndexOrThrow(ContactsContract.Groups._ID)));
			group.setSystemId(cursor.getString(cursor
					.getColumnIndexOrThrow(ContactsContract.Groups.SYSTEM_ID)));
			group.setTitle(gTitle);
			group.setAccountName(cursor.getString(cursor
					.getColumnIndexOrThrow(ContactsContract.Groups.ACCOUNT_NAME)));
			group.setAccountType(cursor.getString(cursor
					.getColumnIndexOrThrow(ContactsContract.Groups.ACCOUNT_TYPE)));
			groupList.add(group);
		}
		cursor.close();
		return groupList;
	}

	private ArrayList<Group> queryGroupsByContactId(String id) {

		ArrayList<Group> groupList = new ArrayList<Group>();
		
		String groupWhere = CommonDataKinds.GroupMembership.CONTACT_ID + " = ? AND " 
			+ CommonDataKinds.GroupMembership.MIMETYPE + " = ?";
		
		String[] groupWhereParams = new String[] { id, 
				CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE };
		
		Cursor cursor = contentResolver.query(Data.CONTENT_URI, null,
				groupWhere, groupWhereParams, null);

		while (cursor.moveToNext()) {
			Group group = new Group();
			group.setId(cursor.getString(cursor
					.getColumnIndexOrThrow(ContactsContract.Groups._ID)));
			group.setTitle(cursor.getString(cursor.getColumnIndex(ContactsContract.Groups.TITLE)));
			
			groupList.add(group);
		}
		cursor.close();
		return null;
	}

	
}
